﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Common.Dynamics.GP.eConnect;

namespace Microsoft.Dynamics.GP.eConnect.Serialization
{
    public static class SOPTransactionTypeExtensions
    {
        //DEFEXTPRICE = 1, lets dynamics do it automatically
        /// <summary>
        /// Calculates and returns document subtotal
        /// </summary>
        /// <param name="sopTransType"></param>
        /// <returns></returns>
        public static decimal CalculateSubTotal(this SOPTransactionType sopTransType)
        {
            if (sopTransType == null) throw new ArgumentNullException("sopTransType");
            if (sopTransType.taSopHdrIvcInsert == null) throw new ArgumentNullException("taSopHdrIvcInsert");
            if (sopTransType.taSopLineIvcInsert_Items == null) throw new ArgumentNullException("taSopLineIvcInsert_Items");
            if (sopTransType.taSopLineIvcInsert_Items.Count() < 1) throw new NullReferenceException("taSopLineIvcInsert_Items");

            decimal subTotal = 0;

            foreach (taSopLineIvcInsert_ItemsTaSopLineIvcInsert lineItem in sopTransType.taSopLineIvcInsert_Items)
                subTotal += lineItem.XTNDPRCE;

            //sopTransType.taSopHdrIvcInsert.SUBTOTAL = subTotal;

            return subTotal;
        }

        /// <summary>
        /// Calulates and sets document subtotal
        /// </summary>
        /// <param name="sopTransType"></param>
        public static void GenerateSubTotal(this SOPTransactionType sopTransType)
        {
            if (sopTransType == null) throw new ArgumentNullException("sopTransType");
            if (sopTransType.taSopHdrIvcInsert == null) throw new ArgumentNullException("taSopHdrIvcInsert");
            if (sopTransType.taSopLineIvcInsert_Items == null) throw new ArgumentNullException("taSopLineIvcInsert_Items");
            if (sopTransType.taSopLineIvcInsert_Items.Count() < 1) throw new NullReferenceException("taSopLineIvcInsert_Items");

            sopTransType.taSopHdrIvcInsert.SUBTOTAL = CalculateSubTotal(sopTransType);
        }

        /// <summary>
        /// Calulates and sets Extended Price
        /// </summary>
        /// <param name="sopTransType"></param>
        public static void GenerateXTNDPRCE(this SOPTransactionType sopTransType)
        {
            if (sopTransType == null) throw new ArgumentNullException("sopTransType");
            if (sopTransType.taSopHdrIvcInsert == null) throw new ArgumentNullException("taSopHdrIvcInsert");
            if (sopTransType.taSopLineIvcInsert_Items == null) throw new ArgumentNullException("taSopLineIvcInsert_Items");
            if (sopTransType.taSopLineIvcInsert_Items.Count() < 1) throw new NullReferenceException("taSopLineIvcInsert_Items");

            for (int i = 0; i < sopTransType.taSopLineIvcInsert_Items.Count(); i++)
                sopTransType.taSopLineIvcInsert_Items[i].XTNDPRCE = sopTransType.taSopLineIvcInsert_Items[i].UNITPRCE * sopTransType.taSopLineIvcInsert_Items[i].QUANTITY;
        }

        /// <summary>
        /// Calculates and returns Tax Amount
        /// </summary>
        /// <param name="sopTransType"></param>
        /// <returns></returns>
        public static decimal CalculateTAXAMNT(this SOPTransactionType sopTransType)
        {
            if (sopTransType == null) throw new ArgumentNullException("sopTransType");
            if (sopTransType.taSopHdrIvcInsert == null) throw new ArgumentNullException("taSopHdrIvcInsert");
            if (sopTransType.taSopLineIvcInsert_Items == null) throw new ArgumentNullException("taSopLineIvcInsert_Items");
            if (sopTransType.taSopLineIvcInsert_Items.Count() < 1) throw new NullReferenceException("taSopLineIvcInsert_Items");

            decimal TAXAMNT = 0;

            foreach (taSopLineIvcInsert_ItemsTaSopLineIvcInsert lineItem in sopTransType.taSopLineIvcInsert_Items)
                TAXAMNT += lineItem.TAXAMNT;

            return TAXAMNT;
        }

        //Subtotal+Freight+Misc+TaxAmt+FreightTax+MiscTax-TradeDisc) = DOCATM
        /// <summary>
        /// Calculates and returns Document Amount
        /// </summary>
        /// <param name="sopTransType"></param>
        /// <returns></returns>
        public static decimal CalculateDOCAMT(this SOPTransactionType sopTransType)
        {
            if (sopTransType == null) throw new ArgumentNullException("sopTransType");
            if (sopTransType.taSopHdrIvcInsert == null) throw new ArgumentNullException("taSopHdrIvcInsert");
            if (sopTransType.taSopLineIvcInsert_Items == null) throw new ArgumentNullException("taSopLineIvcInsert_Items");
            if (sopTransType.taSopLineIvcInsert_Items.Count() < 1) throw new NullReferenceException("taSopLineIvcInsert_Items");

            decimal DOCAMT = (sopTransType.taSopHdrIvcInsert.SUBTOTAL +
                              sopTransType.taSopHdrIvcInsert.FREIGHT +
                              sopTransType.taSopHdrIvcInsert.MISCAMNT +
                              CalculateTAXAMNT(sopTransType) +
                              sopTransType.taSopHdrIvcInsert.FRTTXAMT +
                              sopTransType.taSopHdrIvcInsert.MSCTXAMT -
                              sopTransType.taSopHdrIvcInsert.TRDISAMT);

            return DOCAMT;
        }

        /// <summary>
        /// Calculates and sets Document Amount
        /// </summary>
        /// <param name="sopTransType"></param>
        public static void GenerateDOCAMT(this SOPTransactionType sopTransType)
        {
            if (sopTransType == null) throw new ArgumentNullException("sopTransType");
            if (sopTransType.taSopHdrIvcInsert == null) throw new ArgumentNullException("taSopHdrIvcInsert");
            if (sopTransType.taSopLineIvcInsert_Items == null) throw new ArgumentNullException("taSopLineIvcInsert_Items");
            if (sopTransType.taSopLineIvcInsert_Items.Count() < 1) throw new NullReferenceException("taSopLineIvcInsert_Items");

            sopTransType.taSopHdrIvcInsert.DOCAMNT = CalculateDOCAMT(sopTransType);
        }

        /// <summary>
        /// Calculates and sets Tax Amount
        /// </summary>
        /// <param name="sopTransType"></param>
        public static void GenerateTAXAMNT(this SOPTransactionType sopTransType)
        {
            if (sopTransType == null) throw new ArgumentNullException("sopTransType");
            if (sopTransType.taSopHdrIvcInsert == null) throw new ArgumentNullException("taSopHdrIvcInsert");
            if (sopTransType.taSopLineIvcInsert_Items == null) throw new ArgumentNullException("taSopLineIvcInsert_Items");
            if (sopTransType.taSopLineIvcInsert_Items.Count() < 1) throw new NullReferenceException("taSopLineIvcInsert_Items");

            sopTransType.taSopHdrIvcInsert.TAXAMNT = CalculateTAXAMNT(sopTransType);
        }

        /// <summary>
        /// Returns debit amount based off of Sales, freight (Shipping) and Taxes distributions
        /// </summary>
        /// <param name="sopTransType"></param>
        /// <returns></returns>
        public static decimal CalculateDebitAmount(this SOPTransactionType sopTransType)
        {
            if (sopTransType == null) throw new ArgumentNullException("sopTransType");
            if (sopTransType.taSopDistribution_Items == null) throw new ArgumentNullException("taSopDistribution_Items");
            if (sopTransType.taSopDistribution_Items.Count() < 1) throw new NullReferenceException("taSopDistribution_Items");

            decimal decSubTotal = 0;

            for (int i = 0; i < sopTransType.taSopDistribution_Items.Count(); i++)
            {
                switch (sopTransType.taSopDistribution_Items[i].DISTTYPE.ToType<DistTypes>())
                {
                    case DistTypes.SALES:
                    case DistTypes.TAXES:
                    case DistTypes.FREIGHT:
                        decSubTotal += sopTransType.taSopDistribution_Items[i].CRDTAMNT;
                        break;
                    default:
                        continue;
                }
            }

            return decSubTotal;
        }

        /// <summary>
        /// Gets miscelanneous amount and sets miscelanneous distribution and sets CREATEDIST
        /// </summary>
        /// <param name="sopTransType"></param>
        /// <param name="AccountNumber"></param>
        public static void GenerateMiscDisb(this SOPTransactionType sopTransType, string AccountNumber = "")
        {
            if (sopTransType == null) throw new ArgumentNullException("sopTransType");
            if (sopTransType.taSopHdrIvcInsert == null) throw new ArgumentNullException("taSopHdrIvcInsert");

            List<taSopDistribution_ItemsTaSopDistribution> lstDisb = sopTransType.taSopDistribution_Items.Count() > 0 ? sopTransType.taSopDistribution_Items.ToList() : new List<taSopDistribution_ItemsTaSopDistribution>();

            lstDisb.Add(new taSopDistribution_ItemsTaSopDistribution()
            {
                DISTTYPE = DistTypes.MISC.ToShort(),
                CRDTAMNT = sopTransType.taSopHdrIvcInsert.MISCAMNT,
                ACTNUMST = AccountNumber
            });

            sopTransType.taSopHdrIvcInsert.CREATEDIST = 0;
            sopTransType.taSopDistribution_Items = lstDisb.ToArray();
        }

        /// <summary>
        /// Sets miscelanneous distribution and sets CREATEDIST
        /// </summary>
        /// <param name="sopTransType"></param>
        /// <param name="MiscAmount"></param>
        /// <param name="AccountNumber"></param>
        public static void GenerateMiscDisb(this SOPTransactionType sopTransType, decimal MiscAmount, string AccountNumber = "")
        {
            if (sopTransType == null) throw new ArgumentNullException("sopTransType");
            if (sopTransType.taSopHdrIvcInsert == null) throw new ArgumentNullException("taSopHdrIvcInsert");

            List<taSopDistribution_ItemsTaSopDistribution> lstDisb = sopTransType.taSopDistribution_Items.Count() > 0 ? sopTransType.taSopDistribution_Items.ToList() : new List<taSopDistribution_ItemsTaSopDistribution>();

            lstDisb.Add(new taSopDistribution_ItemsTaSopDistribution()
            {
                DISTTYPE = DistTypes.MISC.ToShort(),
                CRDTAMNT = MiscAmount,
                ACTNUMST = AccountNumber
            });

            sopTransType.taSopHdrIvcInsert.CREATEDIST = 0;
            sopTransType.taSopDistribution_Items = lstDisb.ToArray();
        }

        /// <summary>
        /// Calculates credit amount and sets Freight (Shipping) distribution and sets CREATEDIST
        /// </summary>
        /// <param name="sopTransType"></param>
        /// <param name="AccountNumber"></param>
        public static void GenerateFreightDisb(this SOPTransactionType sopTransType, string AccountNumber = "")
        {
            if (sopTransType == null) throw new ArgumentNullException("sopTransType");
            if (sopTransType.taSopHdrIvcInsert == null) throw new ArgumentNullException("taSopHdrIvcInsert");

            List<taSopDistribution_ItemsTaSopDistribution> lstDisb = sopTransType.taSopDistribution_Items.Count() > 0 ? sopTransType.taSopDistribution_Items.ToList() : new List<taSopDistribution_ItemsTaSopDistribution>();

            lstDisb.Add(new taSopDistribution_ItemsTaSopDistribution()
            {
                DISTTYPE = DistTypes.FREIGHT.ToShort(),
                CRDTAMNT = sopTransType.taSopHdrIvcInsert.FREIGHT,
                ACTNUMST = AccountNumber
            });

            sopTransType.taSopHdrIvcInsert.CREATEDIST = 0;
            sopTransType.taSopDistribution_Items = lstDisb.ToArray();
        }

        /// <summary>
        /// Sets Freight (Shipping) distribution and sets CREATEDIST
        /// </summary>
        /// <param name="sopTransType"></param>
        /// <param name="ShippingAmount"></param>
        /// <param name="AccountNumber"></param>
        public static void GenerateFreightDisb(this SOPTransactionType sopTransType, decimal ShippingAmount, string AccountNumber = "")
        {
            if (sopTransType == null) throw new ArgumentNullException("sopTransType");
            if (sopTransType.taSopHdrIvcInsert == null) throw new ArgumentNullException("taSopHdrIvcInsert");

            List<taSopDistribution_ItemsTaSopDistribution> lstDisb = sopTransType.taSopDistribution_Items.Count() > 0 ? sopTransType.taSopDistribution_Items.ToList() : new List<taSopDistribution_ItemsTaSopDistribution>();

            lstDisb.Add(new taSopDistribution_ItemsTaSopDistribution()
            {
                DISTTYPE = DistTypes.FREIGHT.ToShort(),
                CRDTAMNT = ShippingAmount,
                ACTNUMST = AccountNumber
            });

            sopTransType.taSopHdrIvcInsert.CREATEDIST = 0;
            sopTransType.taSopDistribution_Items = lstDisb.ToArray();
        }

        /// <summary>
        /// Calculates document amount and sets accounts receivable distribution and sets CREATEDIST
        /// </summary>
        /// <param name="sopTransType"></param>
        /// <param name="AccountNumber"></param>
        public static void GenerateAccountsRecvDisb(this SOPTransactionType sopTransType, string AccountNumber = "")
        {
            if (sopTransType == null) throw new ArgumentNullException("sopTransType");
            if (sopTransType.taSopHdrIvcInsert == null) throw new ArgumentNullException("taSopHdrIvcInsert");

            List<taSopDistribution_ItemsTaSopDistribution> lstDisb = sopTransType.taSopDistribution_Items.Count() > 0 ? sopTransType.taSopDistribution_Items.ToList() : new List<taSopDistribution_ItemsTaSopDistribution>();

            lstDisb.Add(new taSopDistribution_ItemsTaSopDistribution()
            {
                DISTTYPE = DistTypes.RECV.ToShort(),
                DEBITAMT = CalculateDOCAMT(sopTransType),
                ACTNUMST = AccountNumber
            });

            sopTransType.taSopHdrIvcInsert.CREATEDIST = 0;
            sopTransType.taSopDistribution_Items = lstDisb.ToArray();
        }

        /// <summary>
        /// Sets accounts receivable distribution and sets CREATEDIST
        /// </summary>
        /// <param name="sopTransType"></param>
        /// <param name="ARAmmount"></param>
        /// <param name="AccountNumber"></param>
        public static void GenerateAccountsRecvDisb(this SOPTransactionType sopTransType, decimal ARAmmount, string AccountNumber = "")
        {
            if (sopTransType == null) throw new ArgumentNullException("sopTransType");
            if (sopTransType.taSopHdrIvcInsert == null) throw new ArgumentNullException("taSopHdrIvcInsert");

            List<taSopDistribution_ItemsTaSopDistribution> lstDisb = sopTransType.taSopDistribution_Items.Count() > 0 ? sopTransType.taSopDistribution_Items.ToList() : new List<taSopDistribution_ItemsTaSopDistribution>();

            lstDisb.Add(new taSopDistribution_ItemsTaSopDistribution()
            {
                DISTTYPE = DistTypes.RECV.ToShort(),
                DEBITAMT = ARAmmount,
                ACTNUMST = AccountNumber
            });

            sopTransType.taSopHdrIvcInsert.CREATEDIST = 0;
            sopTransType.taSopDistribution_Items = lstDisb.ToArray();
        }

        /// <summary>
        /// Calculates credit amount and sets sales distribution and sets CREATEDIST
        /// </summary>
        /// <param name="sopTransType"></param>
        /// <param name="AccountNumber"></param>
        public static void GenerateSalesvDisb(this SOPTransactionType sopTransType, string AccountNumber = "")
        {
            if (sopTransType == null) throw new ArgumentNullException("sopTransType");
            if (sopTransType.taSopHdrIvcInsert == null) throw new ArgumentNullException("taSopHdrIvcInsert");

            List<taSopDistribution_ItemsTaSopDistribution> lstDisb = sopTransType.taSopDistribution_Items.Count() > 0 ? sopTransType.taSopDistribution_Items.ToList() : new List<taSopDistribution_ItemsTaSopDistribution>();

            lstDisb.Add(new taSopDistribution_ItemsTaSopDistribution()
            {
                DISTTYPE = DistTypes.SALES.ToShort(),
                CRDTAMNT = CalculateSubTotal(sopTransType),
                ACTNUMST = AccountNumber
            });

            sopTransType.taSopHdrIvcInsert.CREATEDIST = 0;
            sopTransType.taSopDistribution_Items = lstDisb.ToArray();
        }

        /// <summary>
        /// Sets sales distribution and sets CREATEDIST
        /// </summary>
        /// <param name="sopTransType"></param>
        /// <param name="SalesAmount"></param>
        /// <param name="AccountNumber"></param>
        public static void GenerateSalesvDisb(this SOPTransactionType sopTransType, decimal SalesAmount, string AccountNumber = "")
        {
            if (sopTransType == null) throw new ArgumentNullException("sopTransType");
            if (sopTransType.taSopHdrIvcInsert == null) throw new ArgumentNullException("taSopHdrIvcInsert");

            List<taSopDistribution_ItemsTaSopDistribution> lstDisb = sopTransType.taSopDistribution_Items.Count() > 0 ? sopTransType.taSopDistribution_Items.ToList() : new List<taSopDistribution_ItemsTaSopDistribution>();

            lstDisb.Add(new taSopDistribution_ItemsTaSopDistribution()
            {
                DISTTYPE = DistTypes.SALES.ToShort(),
                CRDTAMNT = SalesAmount,
                ACTNUMST = AccountNumber
            });

            sopTransType.taSopHdrIvcInsert.CREATEDIST = 0;
            sopTransType.taSopDistribution_Items = lstDisb.ToArray();
        }

        /// <summary>
        /// Sets CUSTNMBR in all required places
        /// </summary>
        /// <param name="sopTransType"></param>
        /// <param name="CUSTNMBR"></param>
        public static void SetCUSTNMBR(this SOPTransactionType sopTransType, string CUSTNMBR)
        {
            if (sopTransType == null) throw new ArgumentNullException("sopTransType");
            if (sopTransType.taSopHdrIvcInsert == null) throw new ArgumentNullException("taSopHdrIvcInsert");
            if (sopTransType.taSopLineIvcInsert_Items == null) throw new ArgumentNullException("taSopLineIvcInsert_Items");
            if (CUSTNMBR.isNullOrEmpty()) throw new ArgumentNullException("CUSTNMBR");

            sopTransType.taSopHdrIvcInsert.CUSTNMBR = CUSTNMBR;

            foreach (taSopLineIvcInsert_ItemsTaSopLineIvcInsert lineItem in sopTransType.taSopLineIvcInsert_Items)
                lineItem.CUSTNMBR = CUSTNMBR;
        }
    }
}
